package cn.tedu.csmall.product.service.impl;

import cn.tedu.csmall.commons.pojo.vo.PageData;
import cn.tedu.csmall.commons.web.ServiceCode;
import cn.tedu.csmall.commons.ex.ServiceException;
import cn.tedu.csmall.product.mapper.BrandCategoryMapper;
import cn.tedu.csmall.product.mapper.CategoryAttributeTemplateMapper;
import cn.tedu.csmall.product.mapper.CategoryMapper;
import cn.tedu.csmall.product.mapper.SpuMapper;
import cn.tedu.csmall.product.pojo.entiry.BrandCategory;
import cn.tedu.csmall.product.pojo.entiry.Category;
import cn.tedu.csmall.product.pojo.entiry.CategoryAttributeTemplate;
import cn.tedu.csmall.product.pojo.entiry.Spu;
import cn.tedu.csmall.product.pojo.param.CategoryAddNewParam;
import cn.tedu.csmall.product.pojo.param.CategoryUpdateInfoParam;
import cn.tedu.csmall.product.pojo.vo.CategoryListItemVO;
import cn.tedu.csmall.product.pojo.vo.CategoryStandardVO;
import cn.tedu.csmall.product.pojo.vo.CategoryTreeItemVO;
import cn.tedu.csmall.product.service.ICategoryService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class CategoryServiceImpl implements ICategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private BrandCategoryMapper brandCategoryMapper;
    @Autowired
    private CategoryAttributeTemplateMapper categoryAttributeTemplateMapper;
    @Autowired
    private SpuMapper spuMapper;

    @Override
    public void setDisable(Long id) {
        log.debug("开始执行【禁用类别】业务，参数ID：{}", id);
        updateEnableById(id, 0);
    }

    @Override
    public void setEnable(Long id) {
        log.debug("开始执行【启用类别】业务，参数ID：{}", id);
        updateEnableById(id, 1);
    }

    private void updateEnableById(Long id, Integer enable) {

        // 查询类别是否存在，若不存在，则抛出异常
        CategoryStandardVO standardById = categoryMapper.getStandardById(id);
        if (standardById == null) {
            String message = ENABLE_text[enable] + "类别失败，类别数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 判断查询结果中的enable与参数enable是否相同，如果是，则抛出异常（当前状态与目标状态相同，没必要执行更新）
        if (standardById.getEnable() == enable) {
            String message = ENABLE_text[enable] + "类别失败，此类别已经是" + ENABLE_text[enable] + "状态！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Category category = new Category();
        category.setId(id);
        category.setEnable(enable);
        int rows = categoryMapper.updateById(category);
        if (rows != 1) {
            String message = ENABLE_text[enable] + "类别失败，服务器忙，请稍后再试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public void addNew(CategoryAddNewParam categoryAddNewParam) {
        log.debug("开始处理【添加类别】业务，参数：{}", categoryAddNewParam);

        // 检查类别名称是否被占用，如果被占用，则抛出异常
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", categoryAddNewParam.getName());
        int countByName = categoryMapper.selectCount(queryWrapper);
        log.debug("根据类别名称统计匹配的名称数量，结果：{}", countByName);
        // 判断统计结果是否大于0
        if (countByName > 0) {
            String message = "添加类别失败，类别名称被占用！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 通过参数对象获取parentId
        Long parentId = categoryAddNewParam.getParentId();
        log.debug("父级ID：{}", parentId);
        // 预设depth（深度值）为1
        Integer depth = 1;
        CategoryStandardVO parentCategory = null;
        // 判断parentId是否不为0，若不为0，作为子类，且在父类的深度上+1；若为0，直接作为顶级父类
        if (parentId != 0) {
            //否：调用Mapper对象的getStandardById()方法查询父级类别
            parentCategory = categoryMapper.getStandardById(parentId);
            // 判断查询结果（父级类别）是否为null，如果是，则抛出异常
            if (parentCategory == null) {
                String message = "添加类别失败，父级类别不存在！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
            } else {
                depth = parentCategory.getDepth() + 1;
            }
        }

        // 将类别数据写入到数据库
        // 创建Category对象
        Category category = new Category();
        // 复制属性
        BeanUtils.copyProperties(categoryAddNewParam, category);
        // 补全Category对象的属性值：depth
        category.setDepth(depth);
        // 补全Category对象的属性值：isParent，固定为0
        category.setIsParent(0);
        // 补全Category对象的属性值：数据创建时间
        category.setGmtCreate(LocalDateTime.now());
        // 补全Category对象的属性值：数据最后修改时间
        category.setGmtCreate(LocalDateTime.now());
        // 调用Mapper对象的insert()方法执行插入
        int rows = categoryMapper.insert(category);
        if (rows != 1) {
            String message = "添加类别失败，服务器忙，请稍后再试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("新的类别写入数据库完成！");

        // 添加新的子级后要把父级的【是否为父类】改为1
        // 1. 当前子级的parentId不能是0，是0的话这个子级就是顶级父级，矛盾
        // 2. 父级的isParent等于0，不是父级才能改为父级，已经是父级也没必要改了
        if (parentId != 0 && parentCategory.getIsParent() == 0) {
            // 是：将父级类别的isParent改为1
            Category updateParentCategory = new Category();
            updateParentCategory.setId(parentId);  // 必须提供要修改的类别的ID值
            updateParentCategory.setIsParent(1);
            rows = categoryMapper.updateById(updateParentCategory);
            if (rows != 1) {
                String message = "添加类别失败，服务器忙，请稍后再试！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }
    }

    @Override
    public void delete(Long id) {
        log.debug("开始【根据ID删除类别】业务，参数：{}", id);

        // 尝试删除的数据必须存在
        CategoryStandardVO currentCategory = categoryMapper.getStandardById(id);
        if (currentCategory == null) {
            String message = "删除类别失败，类别名称不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 如果存在关联数据，则不允许删除
        //检查此类别是否关联了品牌
        {
            QueryWrapper<BrandCategory> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("category_id", id);
            int count = brandCategoryMapper.selectCount(queryWrapper);
            if (count > 0) {
                String message = "删除类别失败，当前类别仍关联了品牌！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        //检查此类别是否关联了属性模板
        {
            QueryWrapper<CategoryAttributeTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("category_id", id);
            int count = categoryAttributeTemplateMapper.selectCount(queryWrapper);
            if (count > 0) {
                String message = "删除类别失败，当前类别仍关联了属性模板！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        // 检查此类别是否关联了SPU
        {
            QueryWrapper<Spu> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("category_id", id);
            int count = spuMapper.selectCount(queryWrapper);
            if (count > 0) {
                String message = "删除类别失败，当前类别仍关联了SPU！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        // 判断查询结果中的isParent是否为1，如果是，则抛出异常
        if (currentCategory.getIsParent() == 1) {
            String message = "删除类别失败，该类别仍包含子级类别！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 调用Mapper对象的deleteById()方法执行删除
        int rows = categoryMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除类别失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        // 如果本次删除的是父级中的最后一个子级，则需要将父级的is_parent更新为0
        Long parentId = currentCategory.getParentId();
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        // 统计parentId的数量，如果数量>0,说明还有子级，不能修改父级的is_parent
        int count = categoryMapper.selectCount(queryWrapper);
        // 判断统计结果为0，则将父级类别的isParent更新为0
        if (count == 0) {
            Category category = new Category();
            category.setId(parentId);  // 必须提供要修改的类别的ID值
            category.setIsParent(0);
            category.setGmtModified(LocalDateTime.now());
            rows = categoryMapper.updateById(category);
            if (rows != 1) {
                String message = "删除类别失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }
        log.debug("根据ID删除类别完成！");
    }

    @Override
    public void updateInfoById(Long id, CategoryUpdateInfoParam categoryUpdateInfoParam) {
        log.debug("开始处理【根据id修改类别】业务，参数ID：{},新数据：{}", id, categoryUpdateInfoParam);

        // 检查要修改的数据是否存在，若不存在，则抛出异常
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = categoryMapper.selectCount(queryWrapper);
        log.debug("根据id统计匹配到的数量：{}", countById);
        if (countById == 0) {
            String message = "修改类别名称失败，数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查名称是否被占用
        QueryWrapper<Category> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("name", categoryUpdateInfoParam.getName())
                .ne("id", id);
        int countByName = categoryMapper.selectCount(queryWrapper1);
        log.debug("根据名称相同ID不同统计匹配到的数量：{}", countByName);
        if (countByName > 0) {
            String message = "修改类别名称失败，名称不能重复！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 执行修改
        Category category = new Category();
        BeanUtils.copyProperties(categoryUpdateInfoParam, category);
        category.setId(id);
        category.setGmtModified(LocalDateTime.now());
        int rows = categoryMapper.updateById(category);
        if (rows != 1) {
            String message = "修改类别名称失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }

    }

    @Override
    public CategoryStandardVO getCategoryStandardById(Long id) {
        log.debug("开始处理【根据id查询类别详情】业务，参数ID：{}", id);
        CategoryStandardVO categoryStandardVO = categoryMapper.getStandardById(id);
        if (categoryStandardVO == null) {
            String message = "查询结果失败，类别不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        return categoryStandardVO;
    }

    @Override
    public List<CategoryListItemVO> getCategoryListByParentId(Long parentId) {
        log.debug("开始处理【根据父级id查询子级列表】业务，参数：{}", parentId);
        List<CategoryListItemVO> list = categoryMapper.getListItemByParentId(parentId);
        if (list == null) {
            String message = "查询列表失败，子级列表不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return list;
    }

    @Override
    public List<CategoryTreeItemVO> listTree() {
        log.debug("开始处理【获取类别树】业务，参数：无");

        List<CategoryTreeItemVO> categoryTree = new ArrayList<>();
        List<CategoryListItemVO> categoryListItemVOList = categoryMapper.list();
        Map<Long, CategoryListItemVO> listItemVOMap = convertCategoryToMap(categoryListItemVOList);
        Set<Long> keySet = listItemVOMap.keySet();
        for (Long id : keySet) {
            CategoryListItemVO categoryListItemVO = listItemVOMap.get(id);
            if (categoryListItemVO.getParentId() == 0) {
                CategoryTreeItemVO categoryTreeItemVO = setCategoryTreeItemVO(categoryListItemVO);
                categoryTree.add(categoryTreeItemVO);

                fillChildren(categoryListItemVO, categoryTreeItemVO, listItemVOMap);
            }
        }
        return categoryTree;
    }

    private Map<Long, CategoryListItemVO> convertCategoryToMap(List<CategoryListItemVO> categoryListItemVOList) {
        Map<Long, CategoryListItemVO> allListMap = new LinkedHashMap<>();
        for (CategoryListItemVO listItemVO : categoryListItemVOList) {
            if (listItemVO.getEnable() == 0) {
                continue;
            }
            allListMap.put(listItemVO.getId(), listItemVO);
        }
        return allListMap;
    }

    private CategoryTreeItemVO setCategoryTreeItemVO(CategoryListItemVO categoryListItemVO) {
        return new CategoryTreeItemVO()
                .setValue(categoryListItemVO.getId())
                .setLabel(categoryListItemVO.getName());
    }

    private void fillChildren(CategoryListItemVO listItem, CategoryTreeItemVO currentTree, Map<Long, CategoryListItemVO> allListMap) {
        if (listItem.getIsParent() == 1) {
            currentTree.setChildren(new ArrayList<>());
            Set<Long> keySet = allListMap.keySet();
            for (Long id : keySet) {
                CategoryListItemVO categoryListItemVO = allListMap.get(id);
                if (categoryListItemVO.getParentId() == listItem.getId()) {
                    CategoryTreeItemVO categoryTreeSubItemVO = setCategoryTreeItemVO(categoryListItemVO);
                    currentTree.getChildren().add(categoryTreeSubItemVO);
                    if (categoryListItemVO.getIsParent() == 1) {
                        fillChildren(categoryListItemVO, categoryTreeSubItemVO, allListMap);
                    }
                }
            }
        }

    }
}
